package com.link.base.base.user.service;

import com.link.base.base.appduty.model.AppMenu;
import com.link.base.base.appduty.model.AppSecurityMenu;
import com.link.base.base.appduty.service.AppMenuService;
import com.link.base.base.appduty.service.AppSecurityMenuService;
import com.link.base.base.user.model.AppMenuVO;
import com.link.base.base.user.model.AppSubMenuVO;
import com.link.base.base.user.model.User;
import com.link.base.base.user.dao.mybatis.mapper.LoginMapper;
import com.link.core.basic.service.BasicServiceException;
import com.link.core.cllog.LCLogger;
import com.link.core.basic.database.DataSource;
import com.link.core.basic.database.DataSourceType;
import com.link.core.basic.database.DynamicDataSourceHolder;
import com.link.core.basic.service.KeyGenerateService;
import com.link.core.util.DateUtil;
import com.link.core.util.RedisUtil;
import com.link.core.util.StringUtils;
import com.link.core.util.redisclient.LinkRedisClient;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.stereotype.Service;


import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author unknown
 * @date unknown
 * @comments 用户登录
 */
@Service(value = "loginService")
public class LoginServiceImpl implements LoginService {

    @Resource
    private LoginMapper loginMapper;

    @Resource
    private KeyGenerateService keyGenerateService;
    @Resource
    private AppMenuService appMenuService;

    @Resource
    private AppSecurityMenuService securityMenuService;


    @Override
    @DataSource(DataSourceType.RANDOM)
    public User loadUserByUsername(String username) {
        String[] params = username.split("/");
        username = params[0];
        String corp = "";
        if (params.length > 1) {
            corp = params[1];
        }
        User user = null;
        user = (User) getUser(username, corp);
        try {
            String userRandomDataSourceName = DynamicDataSourceHolder.getRandomSlave(DynamicDataSourceHolder.getRandomDataSourceArr()).getName();
            user.setRandomDataSourceName(userRandomDataSourceName);
            LCLogger.info().withMessageKey("loadUserByUsername")
                    .withMessage("固定了当前用户的随机数据源为：" + userRandomDataSourceName).flush();

            //只在用户名正确地情况下才去校验错误密码登录的次数
            checkLoginErrorTimes(username.toUpperCase());
        }  catch (Exception e) {
            LCLogger.error().withMessageKey("loadUserByUsername")
                    .withMessage(e.getMessage()).flush();
            // throw new BadCredentialsException("系统异常，登录失败");
        }
        return user;
    }

    /**
     * 校验用户名对应的登录错误次数
     *
     * @param username
     */
    private void checkLoginErrorTimes(String username) {
        LinkRedisClient jedis = RedisUtil.getJedis();
        try {
            // 存放用户密码错误信息
            String redisKey = "crm_loginError_info";
            Map<String, String> map = new HashMap<String, String>();
            // 记录当前登录时间
            String currentdate = DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss");

            List<String> fieldList = jedis.exists(redisKey) ? jedis.hmget(redisKey, username) : null;
            if (fieldList != null && fieldList.size() > 0 && fieldList.get(0) != null) {
                String infoStr = fieldList.get(0);
                String str = "\\+";
                if (Integer.parseInt(infoStr.split(str)[0]) >= User.MAX_LOGIN_ERROR_TIME) {
                    Date currentime = new Date();
                    Date lasttime = DateUtil.stringToDate(infoStr.split("\\++")[1], "yyyy-MM-dd HH:mm:ss");
                    int timeSeconds = 1000 * 60 * 60;
                    int two = 2;
                    if ((currentime.getTime() - lasttime.getTime()) / timeSeconds < two) {
                        // throw new BadCredentialsException("用户名密码错误次数过多，系统被锁定");
                    } else {
                        jedis.hdel(redisKey, username);
                        map.put(username, "0" + "+" + currentdate);
                        jedis.hmset(redisKey, map);
                    }
                }
            } else {
                map.put(username, 0 + "+" + currentdate);
                jedis.hmset(redisKey, map);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            RedisUtil.returnResource(jedis);
        }
    }

    @Override
    public void lastLoginDateUpdate(User entity) throws Exception {
        if (entity.getId() == null) {
            throw new Exception("用户ID不能为空。");
        }
        loginMapper.lastLoginDateUpdate(entity);
    }

    @Override
    public User getUser(String username, String corp) {

        if (username == null || "".equals(username.trim())) {
            // throw new BadCredentialsException("用户名不能为空！");
        }
        User user = null;
        User example = new User();
        if (null != username) {
            example.setUsername(username.toUpperCase());
        }
        try {
            user = loginMapper.queryByUsername(example);
            if (StringUtils.isNotBlank(corp) && user != null && !corp.equals(user.getCorpid())) {
                user = null;
            }
        } catch (Exception e) {
            LCLogger.withException(e);
        }
        if (user == null) {
            //throw new BadCredentialsException("找不到用户名为 " + username + " 的用户信息");
            // throw new BadCredentialsException("用户名或密码错误，请重新输入");
        }
        return user;
    }

    @Override
    public List<AppMenuVO> getUserAppMenuList(User user) {

        if (user == null ) {
            throw new BasicServiceException("用户不能为空");
        }
        Long appRole = user.getAppRespId();
        Long corpid = user.getCorpid();
        if (appRole == null) {
            throw new BasicServiceException("此用户没有关联App职责， 请联系管理员添加职责");
        }
        List<AppMenuVO> appMenuVOS = new ArrayList<>();

        List<AppMenu> menuList = appMenuService.queryUserMenus(appRole, corpid);
        //查询菜单的安全性菜单
        List<AppSecurityMenu> securityMenuList = securityMenuService.querySecurityMenu(appRole, corpid);
        Map<Long, List<AppSecurityMenu>> securityMenuGroup = new HashMap<>();
        if (securityMenuList != null && !securityMenuList.isEmpty()) {
            securityMenuGroup = securityMenuList.stream().collect(Collectors.groupingBy(AppSecurityMenu::getParentId));
        }

        //分离出一二级菜单
        if (menuList != null && !menuList.isEmpty()) {
            Map<String, List<AppMenu>> appMenuCollect = menuList.stream().collect(Collectors.groupingBy(AppMenu::getModuleType));
            List<AppMenu> parentMenus = appMenuCollect.get("menu");
            List<AppMenu> subMenus = appMenuCollect.get("sub_menu");

            List<AppSubMenuVO> appSubMenuVOList = new ArrayList<>(subMenus.size());
            if (subMenus != null && !subMenus.isEmpty()) {
                BeanCopier beanCopier = BeanCopier.create(AppMenu.class, AppSubMenuVO.class,false);
                for (AppMenu subMenu : subMenus) {

                    AppSubMenuVO subMenuVO = new AppSubMenuVO();
                    beanCopier.copy(subMenu,subMenuVO,null);
                    subMenuVO.setSecMenus(securityMenuGroup.get(subMenu.getId()));
                    appSubMenuVOList.add(subMenuVO);
                }
            }

            Map<Long, List<AppSubMenuVO>> subMenuGroup = appSubMenuVOList.stream().collect(Collectors.groupingBy(AppSubMenuVO::getParentId));
            if (parentMenus != null && !parentMenus.isEmpty()) {
                BeanCopier parentBeanCopier = BeanCopier.create(AppMenu.class, AppMenuVO.class,false);
                for (AppMenu parentMenu : parentMenus) {
                    AppMenuVO appMenuVO = new AppMenuVO();
                    parentBeanCopier.copy(parentMenu,appMenuVO,null);
                    //子菜单
                    List<AppSubMenuVO> appMenus = subMenuGroup.get(parentMenu.getId());
                    appMenuVO.setSubMenus(appMenus);
                    //安全性菜单
                    appMenuVO.setSecMenus(securityMenuGroup.get(parentMenu.getId()));
                    appMenuVOS.add(appMenuVO);
                }
            }

        }
        return appMenuVOS;
    }

}
